﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PluginService.Common.Sockets;
using PluginService.Common.Model;
using PluginService.Common;
using AopFaceDeteive;
using CommonProjects.FaceDetetive;
using FaceCoreBase.Models;
using System.Drawing;
using CommonProjects.FaceFeatureContex;
using PluginService.DB.Model;
using PluginService.Base;


namespace PluginService
{
    /// <summary>
    /// 配合后台web服务，增加通过socket通讯方式传输数据，没有找到python中的namedpipe解决方案，故用socket
    /// 初始化facedeteive使用web服务
    /// </summary>
    public class AddBlankBySocketAndPipeHelper:FDNamedPiepAndSaveBlankHelper
    {
        #region 变量

        protected AsyncSocketServer<PluginMessage<string>> _socketServer = new AsyncSocketServer<PluginMessage<string>>(8111, 10);

        #endregion

        #region 公共方法

        public override void Start()
        {
            base.Start();
            _socketServer.InitSocket();
            _socketServer.Listen();
        }

        public override void Init()
        {
            base.Init();
            _socketServer.OnConnectedServer += new SocketConnectedHandler<PluginMessage<string>>(OnConnectedServer);
            _socketServer.OnReceivedMessage += new HandleMessageHandler<PluginMessage<string>>(OnReceivedMessage);
        }
        

        #endregion

        #region 受保护函数

        protected override void InitFaceDeteive(string path)
        {
            string url = string.Format("http://{0}/{1}", Consts.WEBSERVER_URL, "get_algithm_config");
            var json_str = Util.GetJsonFromWeb(url);
            if (!string.IsNullOrEmpty(json_str))
            {
                try
                {
                    var config = Newtonsoft.Json.JsonConvert.DeserializeObject<RequestResponseEntity<FaceDeteiveManagerRequest>>(json_str);
                    int threadCount = Convert.ToInt32(config.Data.thread_count);
                    int maxFaceCount = Convert.ToInt32(config.Data.max_face_count);
                    float threshold = config.Data.thresold;
                    int sleepTime = Convert.ToInt32(config.Data.thread_sleep_time);
                    bool isNoticeFailed = false;
                    _faceDeteiveManager = new AopFaceDeteiveManager(threadCount, threshold, maxFaceCount, sleepTime, isNoticeFailed, path + "Config\\Engine.xml");
                    _faceDeteiveManager.OnTopCompareSuccessHander += new TopCompareSuccessHander(FaceDeteiveManager_OnTopCompareSuccessHander);
                    _faceDeteiveManager.Init();
                }
                catch (Exception ex)
                {
                    _log.Error(ex);
                }
            }
            else
            {
                _log.Error("无法从服务获取人脸比对参数，请检测服务");
            }

            //int threadCount = 1;
            //int maxFaceCount = 10;
            //try
            //{
            //    threadCount = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["thread_count"]);
            //    maxFaceCount = Convert.ToInt32(ConfigurationManager.AppSettings["max_face_count"]);
            //    float threshold = Convert.ToSingle(ConfigurationManager.AppSettings["threshold"]);
            //    int sleepTime = Convert.ToInt32(ConfigurationManager.AppSettings["thread_sleep_time"]);
            //    bool isNoticeFailed = Convert.ToBoolean(ConfigurationManager.AppSettings["is_noticed_compare_failed"]);
            //    _faceDeteiveManager = new AopFaceDeteiveManager(threadCount, threshold, maxFaceCount, sleepTime, isNoticeFailed, path + "Config\\Engine.xml");
            //    _faceDeteiveManager.OnTopCompareSuccessHander += new TopCompareSuccessHander(FaceDeteiveManager_OnTopCompareSuccessHander);
            //    //_faceDeteiveManager.Init();

            //}
            //catch (Exception ex)
            //{
            //    _log.Error(ex);
            //    //throw ex;
            //}
        }
        

        protected virtual void OnReceivedMessage(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            if (args != null&&args.Msg!=null)
            {
                switch (args.Msg.PluginMessageType)
                {
                    case PluginMessageType.AddBlank:
                        OnReceivedAddBlankFromSocket(args);
                        break;
                    case PluginMessageType.GetBlank:
                        OnReceiveGetBlankItem(args);
                        break;
                    case PluginMessageType.GetBlankPage:
                        OnReceivedGetBlankItemPage(args);
                        break;
                    case PluginMessageType.GetBlankCount:
                        OnReceivedGetBlankCount(args);
                        break;
                    case PluginMessageType.DelBlankByGuid:
                        OnReceivedDelBlankByGuid(args);
                        break;
                    case PluginMessageType.DelAllBlank:
                        OnReceiveDelAllBlank(args);
                        break;
                }
            }
        }

        protected virtual void OnReceiveDelAllBlank(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            RequestResponseEntity<string> response = new RequestResponseEntity<string>();
            response.Data = "false";
            if (HandReceiveDelAllBlank())
            {
                response.Data = "true";
            }
            try
            {
                var responseData = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                args.AsyncSocketConnect.Socket.Send(args.AsyncSocketConnect.IRecieveArgs.CreateSendMsg(responseData));
            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
            
        }

        protected virtual bool HandReceiveDelAllBlank()
        {
            return _blankFeatureDaoService.ClearBlankFeature();
        }

        protected virtual void RemoveBlankFromFaceDeteiveManager(DelBlankRequest request)
        {
            if (_faceDeteiveManager != null)
            {
                _faceDeteiveManager.RemoveStorageCacheItem(request.Guid);
            }
        }

        protected virtual void OnReceivedDelBlankByGuid(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            RequestResponseEntity<string> response = new RequestResponseEntity<string>();
            response.Data = "false";
            if (args != null)
            {
                try
                {
                    if (args.Msg != null&&args.Msg.MessageBody!=null)
                    {
                        var messageBody = args.Msg.MessageBody;
                        var request = Newtonsoft.Json.JsonConvert.DeserializeObject<DelBlankRequest>(messageBody);
                        if (request != null)
                        {
                            var result = HandDelBlankByGuid(request);
                            if (result)
                            {
                                RemoveBlankFromFaceDeteiveManager(request);
                                response.Data = "true";
                            }
                        }
                        
                    }
                }
                catch (Exception ex)
                {
                    _log.Error(ex);
                }
            }
            try
            {
                var responseData=Newtonsoft.Json.JsonConvert.SerializeObject(response);
                args.AsyncSocketConnect.Socket.Send(args.AsyncSocketConnect.IRecieveArgs.CreateSendMsg(responseData));
            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
        }

        protected virtual bool HandDelBlankByGuid(DelBlankRequest request)
        {
            return _blankFeatureDaoService.DelBlankByGuid(request.Guid);
        }

        protected virtual void OnReceivedGetBlankCount(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            
            if (args != null)
            {
                try
                {
                    int count = HandReceivedGetBlankCount();
                    var data = args.AsyncSocketConnect.IRecieveArgs.CreateSendMsg(count.ToString());
                    args.AsyncSocketConnect.Socket.Send(data);
                }
                catch (Exception ex)
                {
                    _log.Error(ex);
                }
                
            }
        }

        protected virtual int HandReceivedGetBlankCount()
        {
            return _blankFeatureDaoService.GetBlankFeaturesCount(null);
        }

        protected virtual void OnReceivedGetBlankItemPage(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            if (args != null&&args.Msg!=null)
            {
                var messageBody=args.Msg.MessageBody;
                try
                {
                    var request = Newtonsoft.Json.JsonConvert.DeserializeObject<GetPageBlankRequest>(messageBody);
                    var result = HandGetPageBlank(request);
                    if (result != null && result.Count > 0)
                    {
                        var json = Newtonsoft.Json.JsonConvert.SerializeObject(result);
                        var data = args.AsyncSocketConnect.IRecieveArgs.CreateSendMsg(json);
                        args.AsyncSocketConnect.Socket.Send(data);
                    }
                }
                catch(Exception ex)
                {
                    _log.Error(ex);
                }
            }
        }

        protected virtual IList<BlankFeature> HandGetPageBlank(GetPageBlankRequest request)
        {
            return _blankFeatureDaoService.GetBlankFeaturesNoImages(new BlankFeatureQP()
            {
                PageIndex = request.PageIndex,
                PageSize = request.PageSize,
                SkipNum = (request.PageIndex - 1) * request.PageSize
            });
        }

        protected virtual void OnReceiveGetBlankItem(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            BlankFeature result = null;
            var response = new PluginMessage<BlankFeature>();
            if (args != null && args.Msg != null)
            {
                var messageBody = args.Msg.MessageBody;
                try
                {
                    var request = Newtonsoft.Json.JsonConvert.DeserializeObject<GetBlankRequest>(messageBody);
                    result = HandGetBlankItem(request);
                }
                catch(Exception ex)
                {
                    response.Error = ex.Message;
                    _log.Error(ex);
                }
            }
            
            if (result != null)
            {
                response.Result = true;
                response.MessageBody = result;
            }
            else
            {
                response.Result = false;
            }
            var seriableResult = Newtonsoft.Json.JsonConvert.SerializeObject(response);
            try
            {
                args.AsyncSocketConnect.Socket.Send(args.AsyncSocketConnect.IRecieveArgs.CreateSendMsg(seriableResult));
            }
            catch(Exception ex)
            {
                _log.Error(ex);
            }

        }

        protected virtual BlankFeature HandGetBlankItem(GetBlankRequest request)
        {
            if (request != null)
            {
                return _blankFeatureDaoService.GetBlankFeatureByGuid(request.Guid);
            }
            return null;
            
        }

        protected virtual void OnReceivedAddBlankFromSocket(AsyncMessageHandleArgs<PluginMessage<string>> args)
        {
            if (args != null && args.Msg != null && args.Msg.MessageBody!=null)
            {
                var messageBody = args.Msg.MessageBody;
                try
                {
                    var request = Newtonsoft.Json.JsonConvert.DeserializeObject<AddBlankRequest>(messageBody);
                    var result = HandAddBlankRequest(request);
                    if (result != null)
                    {
                        var json = Newtonsoft.Json.JsonConvert.SerializeObject(result);
                        var data = args.AsyncSocketConnect.IRecieveArgs.CreateSendMsg(json);
                        args.AsyncSocketConnect.Socket.Send(data);
                    }
                }
                catch (Exception ex)
                {
                    _log.Error(ex);
                }
            }
        }

        protected virtual PluginMessage<FaceFeatureItem> HandAddBlankRequest(AddBlankRequest request)
        {
            var faceFeatureItem = new CommonProjects.FaceFeatureContex.FaceFeatureItem();
            bool result = false;
            if (request != null)
            {
                if (!string.IsNullOrEmpty(request.ImageBase64Str))
                {
                    try
                    {
                        var bits = Convert.FromBase64String(request.ImageBase64Str);
                        if (bits != null && bits.Length > 0)
                        {
                            if (_faceDeteiveManager != null)
                            {
                                var feature = _faceDeteiveManager.GetFaceFeature(bits);
                                if (feature != null)
                                {
                                    var maxFaceFeature = feature.GetMaxFaceModeRectangle();
                                    
                                    if (maxFaceFeature != null)
                                    {
                                        faceFeatureItem.Id = Guid.NewGuid().ToString("N");
                                        faceFeatureItem.FaceModel = maxFaceFeature.FaceModel;
                                        faceFeatureItem.Feature = maxFaceFeature.FaceModel.Feature;
                                        faceFeatureItem.HttpImageUrl = request.HttpImageUrl;
                                        faceFeatureItem.CustomeId= request.Id;
                                        faceFeatureItem.Name = request.Name;
                                        faceFeatureItem.ImageBase64Str = request.ImageBase64Str;
                                        AddBlankToFaceDeteiveManager(faceFeatureItem);
                                        var drawRetangleStr=DrawImageRectangle(bits, maxFaceFeature);
                                        if (!string.IsNullOrEmpty(drawRetangleStr))
                                        {
                                            faceFeatureItem.ImageBase64Str = drawRetangleStr;
                                        }
                                        SaveBlankToDB(faceFeatureItem);
                                        result = true;
                                    }
                                }
                                else
                                {
                                    _log.Info("can not detected feature");
                                }
                            }
                        }

                    }
                    catch (FormatException ex)
                    {
                        _log.Error("image is not base64str");
                    }
                    catch (Exception ex)
                    {
                        _log.Error(ex);
                    }
                    
                }
            }
            return new PluginMessage<FaceFeatureItem>() {
                Result = result,
                MessageBody = faceFeatureItem
            };
        }

        protected virtual void OnConnectedServer(AsyncSocketConnect<PluginMessage<string>> connect)
        {
        }

        #endregion

        #region private methods

        private string DrawImageRectangle(byte[] imageBits,FaceModelRectangle modle)
        {
            using (var stream = new System.IO.MemoryStream(imageBits))
            {
                System.Drawing.Image image = System.Drawing.Image.FromStream(stream);
                if (image != null)
                {
                    using (Graphics g = Graphics.FromImage(image))
                    {
                        Pen p=new Pen(Color.Red);
                        g.DrawRectangle(p, modle.Rectangle);
                        return Convert.ToBase64String(image.ToJpegBytesV1());

                    }
                }
            }
            return null;
        }

        #endregion

    }
}
